﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Runtime.Remoting.Messaging;
using System.Text;
using SuperSocket.SocketBase;
using SuperSocket.SocketBase.Config;
using SuperSocket.SocketBase.Protocol;
using SuperSocket.SocketEngine;
using SuperWebSocket;
using SuperWebSocket.Protocol;


namespace WebSocketHelper
{
    /// <summary>
    /// Websocket Server 助手 
    /// </summary>
    public class WebSocketHelper
    {
        #region private
        private WebSocketServer wss = null;
        private IBootstrap bootstrap = null;
        private Hashtable HashSession = null;
        private Dictionary<string,WebSocketSession>
                          DictSession = null;
        private Object SyncRoot = null;
        #endregion

        #region Events
        /// <summary>
        /// 当接收到新的二进制数据时引发该事件
        /// </summary>
        public event SessionHandler<WebSocketSession,byte[]> NewDataReceived;
        /// <summary>
        /// 当接收到新的文本数据时引发该事件
        /// </summary>
        public event SessionHandler<WebSocketSession, string> NewMessageReceived;
        /// <summary>
        /// 当接收到新的会话请求是引发该事件
        /// </summary>
        public event RequestHandler<WebSocketSession,IWebSocketFragment> 
                                                        NewRequestReceived;
        /// <summary>
        /// 当新会话连接完成时引发该事件
        /// </summary>
        public event SessionHandler<WebSocketSession> NewSessionConnected;
        /// <summary>
        /// 当丢失或关闭会话连接时引发该事件
        /// </summary>
        public event SessionHandler<WebSocketSession, CloseReason> SessionClosed;
        #endregion

        #region Static
        private static WebSocketHelper _default = new WebSocketHelper();
        /// <summary>
        /// 获取默认服务实例
        /// </summary>
        public static WebSocketHelper Server { get { return _default; } }
        #endregion

        #region Properties
        /// <summary>
        /// 获取当前服务监听端口号
        /// </summary>
        public int Port { get { return this.wss.Config.Port; } }
        /// <summary>
        /// 获取当前服务监听的IP地址
        /// </summary>
        public IPAddress IP { get { return IPAddress.Parse(this.wss.Config.Ip); } }
        /// <summary>
        /// 获取当前服务状态
        /// </summary>
        public ServerState State { get { return this.wss.State; } }
        #endregion

        #region .ctor & .destructor
        private WebSocketHelper()
        {
            HashSession = Hashtable.Synchronized(new Hashtable());
            SyncRoot = new object();
            DictSession = new Dictionary<string, WebSocketSession>();
            wss = new WebSocketServer();
            wss.NewDataReceived += InvokeNewDataReceived;
            wss.NewMessageReceived += InvokeNewMessageReceived;
            wss.NewRequestReceived += InvokeNewRequestReceived;
            wss.NewSessionConnected += InvokeNewSessionConnected;
            wss.SessionClosed += InvokeSessionClosed;
            //wss.Setup(new RootConfig(), new ServerConfig
            //{
            //    Name = "SecureFlowWebSocket",
            //    Ip = "Any",
            //    Port = 43569,
            //    Mode = SocketMode.Tcp,
            //    SyncSend = true,
            //    Security = "tls",
            //    Certificate = new SuperSocket.SocketBase.Config.CertificateConfig
            //    {
            //        FilePath = "all.jackjcsn.com.pfx",
            //        Password = "0951210201"
            //    }
            //});
            wss.Setup(new RootConfig(), new ServerConfig
            {
                Name = "FlowWebSocket",
                Ip = "Any",
                Port = 3569,
                Mode = SocketMode.Tcp
            });

            bootstrap = new DefaultBootstrap(new RootConfig(), new IWorkItem[] { wss });
        }

        ~WebSocketHelper()
        {
            try
            {
                //尝试停止服务
                bootstrap.Stop();
            }
            catch
            {
            }
            finally
            {
                try
                {
                    //尝试释放服务
                    wss.Dispose();
                }
                catch
                {
                }
                finally
                {
                    //尝试清除缓存
                    HashSession.Clear();
                }
            }
        }
        #endregion

        #region Operation

        /// <summary>
        /// 启动服务
        /// </summary>
        public void Start()
        {
            bootstrap.Start();
        }

        /// <summary>
        /// 停止服务
        /// </summary>
        public void Stop()
        {
            bootstrap.Stop();
        }
        #endregion

        #region Message
        /// <summary>
        /// 向所有用户推送文本消息
        /// </summary>
        /// <param name="msg">要发送的文本</param>
        public void SendToAll(string msg)
        {
            var sessions = HashSession.Values;
            foreach (var session in sessions)
            {
                WebSocketSession ws = session as WebSocketSession;
                ws.Send(msg);
            }
        }

        /// <summary>
        /// 向指定的用户推送文本消息
        /// </summary>
        /// <param name="UserID">用户SessionID</param>
        /// <param name="msg">要发送的文本</param>
        public void SendToUser(string UserID, string msg)
        {
            WebSocketSession User = HashSession[UserID] as WebSocketSession;
            User.Send(msg);
        }

        /// <summary>
        /// 想指定的一组用户推送文本消息
        /// </summary>
        /// <param name="UserIDs">包含用户SessionID的列表</param>
        /// <param name="msg">要发送的文本</param>
        public void SendToUsers(IList<string> UserIDs, string msg)
        {
            List<WebSocketSession> Users = new List<WebSocketSession>(UserIDs.Count);
            var  IDs = UserIDs.Distinct();
            lock (HashSession.SyncRoot)
            {
                foreach (string key in IDs)
                {
                    Users.Add(HashSession[key] as WebSocketSession);
                }
            }
            foreach (WebSocketSession ws in Users)
            {
                ws.Send(msg);
            }
        }
        #endregion

        #region Invokers

        /// <summary>
        /// 引发SessionClosed事件
        /// </summary>
        private void InvokeSessionClosed(WebSocketSession session, CloseReason value)
        {
            try
            {
                wss.Logger.DebugFormat("{0} {1} {2}",
                    "SessionClosed", session.SessionID, value.ToString());
                HashSession.Remove(session.SessionID);
                if (SessionClosed != null)
                {
                    IAsyncResult res = 
                       SessionClosed.BeginInvoke(session, value, null, null);
                    SessionClosed.EndInvoke(res);
                }
            }
            catch (Exception ex)
            {
                wss.Logger.Error(ex.Message, ex);
            }
        }

        /// <summary>
        /// 引发NewSessionConnected事件
        /// </summary>
        private void InvokeNewSessionConnected(WebSocketSession session)
        {
            try
            {
#if DEBUG
                wss.Logger.DebugFormat("{0} {1}",
                   "SessionConnected", session.SessionID);
                HashSession.Add(session.SessionID, session);
#endif
                if (NewSessionConnected != null)
                {
                    IAsyncResult r = 
                        NewSessionConnected.BeginInvoke(session, null, null);
                    NewSessionConnected.EndInvoke(r);
                }
            }
            catch (Exception ex)
            {
                wss.Logger.Error(ex.Message, ex);
            }
        }

        /// <summary>
        /// 引发NewRequestReceived事件
        /// </summary>
        private void InvokeNewRequestReceived(WebSocketSession session,
                                              IWebSocketFragment requestInfo)
        {
#if DEBUG
            wss.Logger.DebugFormat("{0} {1}",
                    "NewRequestReceived", session.SessionID);
#endif
            if (NewRequestReceived != null)
            {
                IAsyncResult r = 
                    NewRequestReceived.BeginInvoke(session, requestInfo, null, null);
                NewRequestReceived.EndInvoke(r);
            }
        }

        /// <summary>
        /// 引发NewMessageReceived事件
        /// </summary>
        private void InvokeNewMessageReceived(WebSocketSession session, string value)
        {
#if DEBUG
            wss.Logger.DebugFormat("{0} {1} {2}",
                    "NewMessageReceived", session.SessionID, value);
#endif
            if (NewMessageReceived != null)
            {
                IAsyncResult r = 
                   NewMessageReceived.BeginInvoke(session, value, null, null);
                NewMessageReceived.EndInvoke(r);
            }
        }

        /// <summary>
        /// 引发NewDataReceived事件
        /// </summary>
        private void InvokeNewDataReceived(WebSocketSession session, byte[] value)
        {
#if DEBUG
            wss.Logger.DebugFormat("{0} {1} {2}bytes",
                    "NewDataReceived", session.SessionID, value.LongLength);
#endif
            if (NewDataReceived != null)
            {
                NewDataReceived.BeginInvoke(session, value, null, null);
            }
        }
        #endregion
    }
}
